#include <iostream>
#include <tuple>
#include <functional>
#include <string>
#include <map>
/*
template <unsigned K, class R, class F, class Tup>
struct Expander 
{
    template <class... Us>
        static R expand(F f, Tup&& t, Us... args) 
        {
            return Expander<K - 1, R, F, Tup>::expand(f,
                                                      std::forward<Tup>(t),
                                                      std::get<K - 1>(std::forward<Tup>(t)),
                                                      std::forward<Us>(args)...);
        }
};

template <class F, class R, class Tup> 
struct Expander<0, R, F, Tup> 
{
    template <class... Us> 
        static R expand(F f, Tup&&, Us... args) 
        {
            return f(std::forward<Us>(args)...);
        }
};
template <class F, class... Ts>
auto explode(F&& f, const std::tuple<Ts...>& t)
    -> typename std::result_of<F(Ts...)>::type 
{
    return Expander<sizeof...(Ts),
           typename std::result_of<F(Ts...)>::type,
           F,
           const std::tuple<Ts...>&>::expand(f, t);
}

    template <class F, class... Ts>
auto explode(F&& f, std::tuple<Ts...>& t)
    -> typename std::result_of<F(Ts...)>::type 
{
    return Expander<sizeof...(Ts),
           typename std::result_of<F(Ts...)>::type,
           F,
           std::tuple<Ts...>&>::expand(f, t);
}

    template <class F, class... Ts>
auto explode(F&& f, std::tuple<Ts...>&& t)
    -> typename std::result_of<F(Ts...)>::type 
{
    return Expander<sizeof...(Ts),
           typename std::result_of<F(Ts...)>::type,
           F,
           std::tuple<Ts...>&&>::expand(f, std::forward<std::tuple<Ts...>>(t));
}
*/
template <unsigned K,  class F, class Tup>
struct Expander 
{
    template <class... Us>
        static void expand(F f, Tup&& t, Us... args) 
        {
            Expander<K - 1,  F, Tup>::expand(f,
                                             std::forward<Tup>(t),
                                             std::get<K - 1>(std::forward<Tup>(t)),
                                             std::forward<Us>(args)...);
        }
};

template <class F,  class Tup> 
struct Expander<0,  F, Tup> 
{
    template <class... Us> 
        static void expand(F f, Tup&&, Us... args) 
        {
            f(std::forward<Us>(args)...);
        }
};
    template <class F, class... Ts>
void explode(F&& f, const std::tuple<Ts...>& t)
{
    std::cout<<"1111"<<std::endl;
    Expander<sizeof...(Ts),
           F,
           const std::tuple<Ts...>&>::expand(f, t);
}

    template <class F, class... Ts>
void explode(F&& f, std::tuple<Ts...>& t)
{
    std::cout<<"2222"<<std::endl;
    Expander<sizeof...(Ts),
           F,
           std::tuple<Ts...>&>::expand(f, t);
}

    template <class F, class... Ts>
void explode(F&& f, std::tuple<Ts...>&& t)
{
    std::cout<<"333:"<<sizeof...(Ts)<<std::endl;
    /*
    std::cout<<"333"<<std::endl;
    auto tt = std::forward<std::tuple<Ts...>>(t);
    std::cout<<"args size:"<< std::tuple_size<decltype(tt)>::value<<std::endl;
    */
    Expander<sizeof...(Ts),
           F,
           std::tuple<Ts...>&&>::expand(f, std::forward<std::tuple<Ts...>>(t));
}


void func1(int a)
{
    std::cout<<"func1:"<<a<<std::endl;
}
void func2(int a,std::string b)
{
    std::cout<<"func2:"<<a<<b<<std::endl;
}
void func3(int a,std::string b,float c)
{
    std::cout<<"func3:"<<a<<b<<c<<std::endl;
}
int main()
{
    explode(func1,std::make_tuple(1));
    explode(func2,std::make_tuple(1,std::string("hello world")));
    auto t = std::make_tuple(1,std::string("hello world"));
    explode(func3,std::make_tuple(1,std::string("\thelloworlds"),4.9f));
    std::map<int,int> m;
    m.emplace(1,2);
    return 0;
}


